home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
nos_kit3.zip
/
TNC_ASH.ZIP
/
VDG_KISS.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-05-26
|
48KB
|
1,807 lines
; *********************************************************************
; ** KISS Protocol Program for stock VADCG/ASHBY-2716 KISS V1.03 **
; ** By: Mike Bruski, AJ9X 08FEB87 **
; *********************************************************************
; Change History:
; When Who What
; 26JAN87 AJ9X Initial Version (V1.00)
; 31JAN87 AJ9X Removed auto baud rate detection &
; interval timer driven by 8253 (V1.01)
; 07FEB87 AJ9X Send last character and release cell
; on transmitted async. frames (V1.02)
; 08FEB87 AJ9X Disabled early end of frame interrupt
; from 8273 to prevent transmitter
; shutdown prior to sending CRC and
; closing flag (V1.03)
; PAGE
;
; 8250 SIO Controller Equates
; Registers:
RBR EQU 0 ; RECEIVE BUFFER REGISTER [R]
THR EQU 0 ; TRANSMIT HOLDING REGISTER [W]
DLL EQU 0 ; DRIVER LATCH (LSB) [W]
DLM EQU 1 ; DRIVER LATCH (MSB) [W]
IER EQU 1 ; INTERRUPT ENABLE REGISTER [W]
IIR EQU 2 ; INTERRUPT IDENTIFICATION REGISTER [R]
LCR EQU 3 ; LINE CONTROL REGISTER [R/W]
MCR EQU 4 ; MODEM CONTROL REGISTER [R/W]
LSR EQU 5 ; LINE STATUS REGISTER [R/W]
MSR EQU 6 ; MODEM STATUS REGISTER [R/W]
; Equates for Interrupt Enable Register
ERI EQU 00000001B ; ENABLE RECEIVE DATA INTERRUPTS
ETI EQU 00000010B ; ENABLE TRANSMIT DATA INTERRUPTS
ELI EQU 00000100B ; ENABLE LINE STATUS INTERRUPTS
EMI EQU 00001000B ; ENABLE MODEM STATUS INTERRUPTS
; Equates for Line Status Register
DR EQU 00000001B ; DATA READY
OE EQU 00000010B ; OVERRUN ERROR
PE EQU 00000100B ; PARITY ERROR
FE EQU 00001000B ; FRAMING ERROR
BI EQU 00010000B ; BREAK INTERRUPT
THRE EQU 00100000B ; TRANSMIT HOLDING REGISTER EMPTY
TSRE EQU 01000000B ; TRANSMIT SHIFT REGISTER EMPTY
; Equates for Modem Status Register
DCTS EQU 00000001B ; DELTA CLEAR-TO-SEND
DDSR EQU 00000010B ; DELTA DATA-SET-READY
TERI EQU 00000100B ; TRAILING EDGE OF RING INDICATOR
DCD EQU 00001000B ; DELTA CARRIER DETECT
TCTS EQU 00010000B ; TERMINAL CLEAR-TO-SEND
TDSR EQU 00100000B ; TERMINAL DATA-SET-READY
TRI EQU 01000000B ; TERMINAL RING INDICATOR
TCD EQU 10000000B ; TERMINAL CARRIER DETECT
; Equates for Line Control Register
D5 EQU 00000000B ; WORD LENGTH = 5 BITS
D6 EQU 00000001B ; WORD LENGTH = 6 BITS
D7 EQU 00000010B ; WORD LENGTH = 7 BITS
D8 EQU 00000011B ; WORD LENGTH = 8 BITS
S1 EQU 00000000B ; STOP BITS = 1
S2 EQU 00000100B ; STOP BITS = 2
NP EQU 00000000B ; NO PARITY
PEN EQU 00001000B ; PARITY ENABLE
OP EQU 00000000B ; ODD PARITY
EP EQU 00010000B ; EVEN PARITY SELECT
STP EQU 00100000B ; STICK PARITY
SB EQU 01000000B ; SET BREAK
DLA EQU 10000000B ; DIVISOR LATCH ACCESS
; Equates for Modem Control Register
ADTR EQU 00000001B ; ASYNCHRONOUS DATA-TERMINAL-READY
ARTS EQU 00000010B ; ASYNCHRONOUS REQUEST-TO-SEND
OUT1 EQU 00000100B ; ASYNCHRONOUS CARRIER DETECT (LOOP=RI)
OUT2 EQU 00001000B ; NO CONNECTION ON VADCG (LOOP=CD)
LOOP EQU 00010000B ; LOOPBACK DIAGNOSTIC ENABLE
; Equates for Interrupt Identification Register
AIPM EQU 00000001B ; ASYNC INT. PENDING MASK
; INTERRUPT IS PENDING IF NOT SET
IIM EQU 00000110B ; INTERRUPT IDENTIFICATION MASK
RLSI EQU 00000110B ; RECEIVER LINE STATUS INTERRUPT
RDAI EQU 00000100B ; RECEIVED DATA AVAILABLE INTERRUPT
TREI EQU 00000010B ; TRANSMIT HOLDING REG. EMPTY INTERRUPT
MSI EQU 00000000B ; MODEM STATUS INTERRUPT
; PAGE
;
; 8273 HDLC Controller Equates
; Registers:
STAT73 EQU 10H ; STATUS REGISTER [R]
CMND73 EQU 10H ; COMMAND REGISTER [W]
PARM73 EQU 11H ; PARAMETER REGISTER [W]
RESL73 EQU 11H ; RESULTS REGISTER [R]
TEST73 EQU 12H ; TEST REGISTER [W]
TXIR73 EQU 12H ; TRANSMIT INTERRUPT RESULTS REGISTER[R]
RXIR73 EQU 13H ; RECEIVE INTERRUPT RESULTS REGISTER [R]
TXDR73 EQU 18H ; TRANSMIT DATA REGISTER [W]
RXDR73 EQU 20H ; RECEIVE DATA REGISTER [R]
; Equates for STAT73
TXIRA EQU 00000001B ; TRANSMIT INTERRUPT RESULTS AVAILABLE
RXIRA EQU 00000010B ; RECEIVE INTERRUPT RESULTS AVAILABLE
TINTP EQU 00000100B ; TRANSMIT INTERRUPT STILL PENDING
RINTP EQU 00001000B ; RECEIVE INTERRUPT STILL PENDING
CRBF EQU 00010000B ; COMMAND RESULTS BUFFER FULL
CPBF EQU 00100000B ; COMMAND PARAMETER BUFFER FULL
CBF EQU 01000000B ; COMMAND BUFFER FULL
CBSY EQU 10000000B ; COMMAND BUFFER BUSY
; Equates for TXIR73
EXI EQU 00001100B ; EARLY TRANSMIT INTERRUPT
FTC EQU 00001101B ; FRAME TRANSMISSION COMPLETE
DMAU EQU 00001110B ; DMA UNDERRUN (not used)
CTSE EQU 00001111B ; CLEAR-TO-SEND ERROR
ATC EQU 00010000B ; ABORT TRANSMISSION COMPLETE
; Equates for RXIR73
CRCE EQU 00000011B ; CRC ERROR
FAD EQU 00000100B ; FRAME ABORT DETECTED
IFD EQU 00000101B ; IDLE FLAG DETECTED
EOPD EQU 00000110B ; EOP DETECTED (not used)
SFD EQU 00000111B ; SHORT FRAME DETECTED (< 32 BITS)
DMAO EQU 00001000B ; DMA OVERRUN
MBO EQU 00001001B ; MEMORY BUFFER OVERFLOW
CDF EQU 00001010B ; CARRIER DETECT FAILURE
RIO EQU 00001011B ; RECEIVE INTERRUPT OVERRUN
; Equates for PORT A (input)
MCTS EQU 00000001B ; MODEM CLEAR-TO-SEND
MCD EQU 00000010B ; MODEM CARRIER DETECT
PA2 EQU 00000100B ; SPARE PORT INPUT
PA3 EQU 00001000B ; SPARE PORT INPUT
PA4 EQU 00010000B ; SPARE PORT INPUT
; Equates for PORT B (output)
MRTS EQU 00000001B ; MODEM REQUEST-TO-SEND
PB1 EQU 00000010B ; SPARE PORT OUTPUT
PB2 EQU 00000100B ; SPARE PORT OUTPUT
PB3 EQU 00001000B ; SPARE PORT OUTPUT
PB4 EQU 00010000B ; SPARE PORT OUTPUT
FD EQU 00100000B ; FLAG DETECT
; PAGE
;
; 8253 Interval Timer Equates (VDS-1 only)
; Registers:
PIT0 EQU 28H ; COUNTER PORT 0 (8273 BAUD RATE)
PIT1 EQU 29H ; COUNTER PORT 1 (8085 TRAP)
PIT2 EQU 2AH ; COUNTER PORT 2
ITCP EQU 2BH ; INTERVAL TIMER CONTROL PORT
; Equates for ITCP (control word)
; Register selection field
C0 EQU 00000000B ; COUNTER 0
C1 EQU 01000000B ; COUNTER 1
C2 EQU 10000000B ; COUNTER 2
; Read/Load control field
LC EQU 00000000B ; LATCH COUNT
RLL EQU 00010000B ; READ/LOAD LSB ONLY
RLM EQU 00100000B ; READ/LOAD MSB ONLY
RLB EQU 00110000B ; READ/LOAD LSB FIRST, MSB NEXT
; Mode control field
MD0 EQU 00000000B ; MODE 0, TIMED INTERRUPT
MD1 EQU 00000010B ; MODE 1, RETRIGGERABLE ONE SHOT
MD2 EQU 00000100B ; MODE 2, RATE GENERATOR
MD3 EQU 00000110B ; MODE 3, SQUARE WAVE GENERATOR
MD4 EQU 00001000B ; MODE 4, SOFTWARE TRIGGERED STROBE
MD5 EQU 00001010B ; MODE 5, HARDWARE TRIGGERED STROBE
; Counter Type field
BIN EQU 00000000B ; 16 BIT BINARY
BCD EQU 00000001B ; 4 DECADE BCD
; Equates for PIT0 (Synchronous Baud Rate Values)
SBR9600 EQU 4 ; 9600 baud
SBR4800 EQU 8 ; 4800 baud
SBR2400 EQU 16 ; 2400 baud
SBR1200 EQU 32 ; 1200 baud (default)
SBR600 EQU 64 ; 600 baud
SBR300 EQU 128 ; 300 baud
; Equates for PIT1 (Cyclic Timer) - NOT USING THIS YET
; Input = 38.4Khz from pin 4 of U40
MS100 EQU 3840 ; 100ms timer value
MS50 EQU 1920 ; 50ms timer value
MS20 EQU 768 ; 20ms timer value
MS10 EQU 384 ; 10ms timer value (default)
; Use these guys for S/W timing (now for all VADCG & ASHBY)
IC100 EQU 2297 ; Interval count for 100ms
IC10 EQU 230 ; Interval count for 10ms
; Equates for PIT2 (Random Number Generator)
; Input = 38.4Khz from pin 4 of U40
SEED EQU 32767
; PAGE
;
; 8085 CPU Interrupt Mask Register Equates
ACD EQU 00000001B ; RST5.5, ASYNC. INTERRUPTS DISABLED
STD EQU 00000010B ; RST6.5, SYNC. XMTR INT. DISABLED
SRD EQU 00000100B ; RST7.5, SYNC. RCVR INT. DISABLED
MSE EQU 00001000B ; INTERRUPT MASK ENABLED
;
; Special Character Equates
EOS EQU 00H
LF EQU 0AH
CR EQU 0DH
COMMA EQU 2CH
PERIOD EQU 2EH
FEND EQU 0C0H
FESC EQU 0DBH
TFEND EQU 0DCH
TFESC EQU 0DDH
;
; End Action (Event) Flags
SRFC EQU 00000001B ; SYNC. RECEIVER FRAME COMPLETION
ARFC EQU 00000010B ; ASYNC. RECEIVER FRAME COMPLETION
STFC EQU 00000100B ; SYNC. TRANSMITTER FRAME COMPLETION
ATFC EQU 00001000B ; ASYNC. TRANSMITTER FRAME COMPLETION
EXTI EQU 00010000B ; EXPIRED TIMER
SRDD EQU 00100000B ; SYNC. RECEIVER DISCARDING DATA
ARDD EQU 01000000B ; ASYNC. RECEIVER DISCARDING DATA
;
; Miscellaneous Equates
WDVAL EQU 220 ; DEFAULT WATCH DOG DELAY FOR 1200 BAUD
; PAGE
;
; Static Random Access Memory (SRAM) Equates
; LORAM HIRAM CONFIGURATION
;
; 1000H 1FFFH *ASHBY with 2716 ROMs or Standard VADCG
; 2000H 2FFFH ASHBY with 2732 ROMs
; 7000H 7FFFH VADCG with California memory mods
; 8000H 8FFFH VADCG with early AMRAD memory mods
; 8000H 9FFFH VADCG with VDS-1 (8K RAM)
; 8000H FFFFH VADCG with VDS-1 (32K RAM)
;
LORAM EQU 1000H ; BEGINNING OF SRAM
HIRAM EQU 1FFFH ; END OF SRAM
STACK EQU LORAM+64H ; BEGINNING OF PROGRAM STACK
EA$FLG EQU STACK+2 ; END ACTION FLAGS
; Interval Timer Variables
PVAL EQU EA$FLG+1 ; PERSISTENCE VALUE
SVAL EQU PVAL+1 ; SLOT-TIME VALUE
RVAL EQU SVAL+1 ; RELAY DELAY VALUE
TVAL EQU RVAL+1 ; SQUELCH TAIL DELAY VALUE
TICKS EQU TVAL+1 ; TICK COUNTER FOR S/W TIMING
IT$FLG EQU TICKS+2 ; 0 = INACTIVE, 1 = ACTIVE
IT$VAL EQU IT$FLG+1 ; CURRENT TIMER VALUE
IT$STA EQU IT$VAL+2 ; CURRENT TIMER STATE
; Asynchronous Receiver Variables
AR$HC EQU IT$STA+1 ; CURRENT FRAME HEAD
AR$BP EQU AR$HC+2 ; CURRENT BUFFER POINTER
AR$FSZ EQU AR$BP+2 ; CURRENT FRAME SIZE
AR$FH EQU AR$FSZ+2 ; COMPLETED FRAME HEAD
AR$FS EQU AR$FH+2 ; COMPLETED FRAME SIZE
AR$STA EQU AR$FS+2 ; CURRENT MACHINE STATE
; Asynchronous Transmitter Variables
AT$BP EQU AR$STA+1 ; CURRENT BUFFER POINTER
AT$QS EQU AT$BP+2 ; QUEUE SIZE
AT$QR EQU AT$QS+1 ; QUEUE READ POINTER
AT$QW EQU AT$QR+2 ; QUEUE WRITE POINTER
AT$STA EQU AT$QW+2 ; CURRENT MACHINE STATE
; Synchronous Receiver Variables
SR$HC EQU AT$STA+1 ; CURRENT FRAME HEAD
SR$BP EQU SR$HC+2 ; CURRENT BUFFER POINTER
SR$FR EQU SR$BP+2 ; CURRENT FRAME RESULTS
SR$STA EQU SR$FR+1 ; CURRENT MACHINE STATE
; Synchronous Transmitter Variables
ST$BP EQU SR$STA+1 ; CURRENT BUFFER POINTER
ST$FR EQU ST$BP+2 ; CURRENT FRAME RESULTS
ST$QS EQU ST$FR+1 ; QUEUE SIZE
ST$QR EQU ST$QS+1 ; QUEUE READ POINTER
ST$QW EQU ST$QR+2 ; QUEUE WRITE POINTER
; Synchronous Command Buffers
SRACT EQU ST$QW+2 ; RECEIVER ACTIVATION COMMAND
STACT EQU SRACT+4 ; TRANSMITTER ACTIVATION COMMAND
; Asynchronous Transmitter Queue
AT$QT EQU STACT+4 ; TOP OF QUEUE
AT$QB EQU AT$QT+(2*64) ; BOTTOM OF QUEUE
; Synchronous Transmitter Queue
ST$QT EQU AT$QB+2 ; TOP OF QUEUE
ST$QB EQU ST$QT+(4*64) ; BOTTOM OF QUEUE
; Buffer area
FL$HC EQU ST$QB+4
NCELL EQU (HIRAM-FL$HC+2)/128
BAREA EQU (HIRAM-NCELL*128)+1 ; BEGINNING OF BUFFER AREA
NLIST EQU BAREA-2 ; # OF AVAILABLE CELLS IN FREE LIST
; PAGE
BASE EQU 0
ORG BASE ; PROGRAM ORIGIN
;
; Here we begin -
; A good place to start is with the interrupt vectors
;
; RST0 - [H/W AND S/W INTERRUPT]
; ENTER HERE ON POWER UP AND WHEN THE RESET
; BUTTON IS SMASHED TO INITIALIZE THE H/W
; AND MEMORY. MIGHT ALSO VECTOR HERE IN S/W
; IF EVERYTHING IS SO MESSED UP THE TNC CAN'T
; FUNCTION CORRECTLY.
RST0 EQU $ ; RESTART (WARM & COLD)
JMP INIT
ORG BASE+08H
;
; RST1 - [S/W INTERRUPT]
; ENTER HERE TO RETURN FROM AN INTERRUPT. THE FIRST
; ITEM ON THE STACK WILL BE A RETURN ADDRESS TO THE
; RST INSTRUCTION WHICH GOT US HERE SO IT GETS WASTED.
; NEXT THE PROGRAM STATUS WORD (ACCUMULATOR & FLAGS)
; ARE RESTORE, INTERRUPTS ARE RE-ENABLED AND THE REST
; IS HISTORY.
RST1 EQU $
POP PSW ; PURGE BOGUS ADDRESS FROM STACK
POP PSW ; RESTORE PROGRAM STATUS WORD
EI ; UNGATE INTERRUPTS
RET ; RETURN TO POINT OF INTERRUPT
ORG BASE+10H
;
; RST2 - [S/W INTERRUPT]
; NO FUNCTION
RST2 EQU $
RET
ORG BASE+18H
;
; RST3 - [S/W INTERRUPT]
; NO FUNCTION
RST3 EQU $
RET
ORG BASE+20H
;
; RST4 - [S/W INTERRUPT]
; NO FUNCTION
RST4 EQU $
RET
ORG BASE+24H
;
; TRAP - [NON MASKABLE H/W INTERRUPT]
; NOT USED
TRAP EQU $
EI
RET
ORG BASE+28H
;
; RST5 - [S/W INTERRUPT]
; NO FUNCTION
RST5 EQU $
RET
ORG BASE+2CH
;
; RST5.5 - [MASKABLE H/W INTERRUPT]
; VECTOR HERE WHEN A SIGNAL IS DETECTED ON PIN 9 OF
; THE 8085. THE 8250 WILL ASSERT THIS PIN WHEN ONE
; OF THE FOLLOWING OCCURS; TRANSMIT BUFFER EMPTY,
; RECEIVE CHARACTER AVAILABLE, RECEIVER OVERRUN,
; RECEIVER PARITY ERROR, RECEIVER FRAMING ERROR,
; BREAK INTERRUPT, DELTA CTS, DELTA DSR, RING INDICATE
; OR RECEIVE LINE SIGNAL DETECT.
RST55 EQU $
JMP AIRC ; GOTO ASYNC. INTERRUPT RESPONSE CODE
ORG BASE+30H
;
; RST6 - [S/W INTERRUPT]
; NO FUNCTION
RST6 EQU $
RET
ORG BASE+34H
;
; RST6.5 - [MASKABLE H/W INTERRUPT]
; VECTOR HERE WHEN A SIGNAL IS DETECTED ON PIN 8 OF
; THE 8085. THE 8273 WILL ASSERT THIS PIN WHEN THE
; SYNCHRONOUS TRANSMITTER REQUIRES SERVICE.
RST65 EQU $
JMP STIRC ; GOTO SYNC. XMTR INTERRUPT RESPONSE CODE
ORG BASE+38H
;
; RST7 - [S/W INTERRUPT]
; NO FUNCTION
RST7 EQU $
RET
ORG BASE+3CH
;
; RST7.5 - [MASKABLE H/W INTERRUPT]
; VECTOR HERE WHEN A SIGNAL IS DETECTED ON PIN 7 OF
; THE 8085. THE 8273 WILL ASSERT THIS PIN WHEN THE
; SYNCHRONOUS RECEIVER REQUIRES SERVICE.
RST75 EQU $
JMP SRIRC ; GOTO SYNC. RCVR INTERRUPT RESPONSE CODE
; PAGE
;
; Initialize Hardware
; Branch here for critical S/W errors or H/W reset
; Begin by reseting the 8250, 8253, and 8273
INIT EQU $
DI ; GATE INTERRUPTS
MVI A,1 ; FIRST HALF OF 8273 RESET COMMAND
OUT TEST73 ; ISSUE COMMAND
; Book says to delay at least 10 tcycles then issue second half
XRA A ; A <-- 0 [ 4 tcy]
OUT MCR ; DROP 8250 DTR & RTS [10 tcy]
OUT IER ; KILL 8250 INTERRUPTS [10 tcy]
; This should be enough delay
OUT TEST73 ; SECOND HALF OF 8273 RESET COMMAND
IN RBR ; FLUSH THE 8250 INPUT REGISTER
IN RBR
; H/W is now in an acceptable state, continue
LXI SP,STACK ; SET STACK POINTER
; Now clear SRAM
LXI D,HIRAM ; DE <-- HIGH SRAM ADDRESS
LXI H,LORAM ; HL <-- LOW SRAM ADDRESS
INIT1 EQU $
MVI M,0 ; CLEAR NEXT LOCATION
INX H ; INCREMENT POINTER
MOV A,D ; A <-- MSB OF HIGH ADDRESS
CMP H
JNZ INIT1 ; IF (D <> H) GOTO INIT1
MOV A,E ; A <-- LSB OF HIGH ADDRESS
CMP L
JNZ INIT1 ; IF (E <> L) GOTO INIT1
MVI M,0 ; ZERO LAST RAM LOCATION
; Initialize linked list of free cells
MVI A,NCELL ; A <-- # OF CELLS
STA NLIST ; SAVE IN SRAM
MOV B,A ; NOW MOVE CELL COUNT TO B
LXI D,BAREA ; DE <-- ADDRESS OF BUFFER AREA
DCR B ; SO THAT LAST CELL IS 0
INIT2 EQU $
LXI H,128 ; HL <-- CELL SIZE
DAD D ; HL <-- ADDRESS OF NEXT CELL
XCHG ; DE <-- NEXT, HL <-- CURRENT
MOV M,E ; CURRENT GETS LSB OF NEXT
INX H
MOV M,D ; FOLLOWED BY MSB OF NEXT
DCR B ; B <-- B-1
JNZ INIT2 ; IF (B <> 0) GOTO INIT2
; Initialize state variables
MVI A,7
STA AR$STA
MVI A,0FFH
STA AT$STA
; Initialize queue variables
LXI H,AT$QT
SHLD AT$QR
SHLD AT$QW
LXI H,ST$QT
SHLD ST$QR
SHLD ST$QW
; Initialize miscellaneous variables
LXI H,0C002H ; GENERAL RECEIVE COMMAND (8273)
SHLD SRACT
LXI H,330 ;*;; MAXIMUM ALLOWABLE PACKET LENGTH
SHLD SRACT+2
LXI H,0C802H ; TRANSMIT FRAME COMMAND (8273)
SHLD STACT
LXI H,BAREA ; H <-- ADDRESS OF FREE CELL AREA
SHLD FL$HC ; ESTABLISH FREE LIST HEAD CELL
LXI H,MS10 ; H <-- CONSTANT FOR 10MS S/W TIMING
SHLD TICKS ; PRELOAD S/W COUNT VARIABLE
MVI A,2 ; DEFAULT SQUELCH TAIL DELAY (20ms)
STA TVAL
MVI A,5 ; DEFAULT SLOT-TIME DELAY (50ms)
STA SVAL
MVI A,30 ; DEFAULT RELAY DELAY (300ms)
STA RVAL
MVI A,128 ; DEFAULT PERSISTENCE VALUE (0.5)
STA PVAL
; Establish baud rate for asynchronous port
LXI H,32 ; CONSTANT FOR 4800 BAUD
MVI A,DLA ; A <-- DIVISOR LATCH ACCESS FLAG
OUT LCR ; WRITE LINE CONTROL REGISTER
MOV A,L ; A <-- LSB OF BAUD RATE CONSTANT
OUT DLL ; WRITE DIVISOR LATCH LSB
MOV A,H ; A <-- MSB OF SAME
OUT DLM ; WRITE DIVISOR LATCH MSB
MVI A,NP+D8+S2 ; NO PARITY, 8 DATA BITS, 2 STOP BITS
OUT LCR ; WRITE LINE CONTROL REGISTER
;**********************************************************************
; The following code segment is for VDS-1 users only!!!
; Erase ';*;' in columns 1 thru 3 to assemble this segment.
; Establish baud rate for synchronous port
;*; MVI A,C0+RLB+MD3+BIN ; 8253 MODE CONTROL WORD
;*; OUT ITCP ; WRITE INTERVAL TIMER CONTROL PORT
;*; LXI H,SBR1200 ; CONSTANT FOR 1200 BAUD
;*; MOV A,L ; A <-- LSB
;*; OUT PIT0 ; WRITE
;*; MOV A,H ; A <-- MSB
;*; OUT PIT0 ; WRITE
; Activate the random number generator.
;*; MVI A,C2+RLB+MD3+BIN ; MODE CONTROL WORD
;*; OUT ITCP ; WRITE
;*; LXI H,SEED ; COUNTER VALUE
;*; MOV A,L ; A <-- LSB
;*; OUT PIT2 ; WRITE
;*; MOV A,H ; A <-- MSB
;*; OUT PIT2 ; WRITE
;**********************************************************************
; Asynchronous controller activation
; RST5.5 to CPU is enabled first
MVI A,ERI+ELI+EMI ; RECEIVE AND LINE STATUS ENABLE
OUT IER ; WRITE INTERRUPT ENABLE REGISTER
MVI A,ADTR+ARTS+OUT1 ; DTR, RTS, & CD FOR HOST
OUT MCR ; WRITE MODEM CONTROL REGISTER
; Synchronous controller activation follows
LXI H,DTRANS
CALL SCMDOT ; SET DATA XFER MODE
LXI H,OPMODE
CALL SCMDOT ; SET OPERATING MODE
LXI H,SERIO
CALL SCMDOT ; SET SERIAL I/O MODE
LXI H,SSDTR
CALL SCMDOT ; SET SYNCH. DTR TO MODEM
CALL GCELL ; GET A FREE CELL
XCHG ; HL <-- CELL POINTER
SHLD SR$BP ; ESTABLISH NEW POINTERS
SHLD SR$HC
MVI M,0 ; RESET FORWARD POINTER
INX H ; ADVANCE POINTER
MVI M,0
MVI A,MSE ; UNGATE RST5.5,RST6.5, & RST7.5
DB 30H ; 8085 SIM INSTRUCTION
LXI H,SRACT ; SYNC. RECEIVER ACTIVATION COMMAND
CALL SCMDOT
; LIGHTS! CAMERA! ACTION!
EI
; PAGE
; TNC Executive Routine
EXEC EQU $
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA A
JNZ EXEC2 ; IF (FLAGS SET) GOTO EXEC2
LDA IT$FLG ; A <-- TIMER CONTROL FLAG
ORA A
JNZ EXEC1 ; IF (TIMER ACTIVE) GOTO EXEC1
LXI H,RPA ; HL <-- READ PORT A COMMAND
CALL SCMDOT ; ISSUE COMMAND
CALL SRSLIN ; READ RESULTS
ANI MCD ; MASK MODEM CARRIER DETECT
JNZ EXEC ; IF (CHANNEL BUSY) GOTO EXEC
LDA ST$QS ; A <-- SYNC. XMTR QUEUE SIZE
ORA A
JZ EXEC ; IF (EMPTY QUEUE) GOTO EXEC
;**********************************************************************
; The following code segment is for VDS-1 users only!!!
; Remove ';*; in column 1 thru 3 to assemble this segment.
; ASHBY and non-VDS VADCGs are rendered totally non-persistent
;*; MVI A,C2+RLL ; READ CONTROL WORD
;*; OUT ITCP ; WRITE INTERVAL TIMER CONTROL PORT
;*; IN PIT2 ; READ LSB OF TIMER (OUR RANDOM #)
;*; MOV B,A ; COPY TO B FOR NOW
;*; LDA PVAL ; A <-- PERSISTENCE VALUE
;*; SUB B
;*; JNC A5$S0A ; IF (RANDOM < PVAL) GOTO A5$S0A
;**********************************************************************
LDA SVAL ; A <-- SLOT-TIME VALUE
MOV L,A ; COPY TO L
XRA A
MOV H,A ; EXTEND 16 BITS
SHLD IT$VAL ; ESTABLISH TIMER VALUE
STA IT$STA ; RECORD NEW STATE
INR A
STA IT$FLG ; ACTIVATE TIMER
JMP EXEC
; Active timer processing
EXEC1 EQU $
LHLD TICKS ; HL <-- S/W TIMER COUNT
DCX H ; DECREMENT
SHLD TICKS ; RECORD NEW COUNT
MOV A,L ; A <-- LSB OF COUNT
ORA H ; MSB
JNZ EXEC ; IF (NOT 0) GOTO EXEC
LXI H,MS10 ; 10ms TIMER CONSTANT
SHLD TICKS ; RELOAD COUNT
LHLD IT$VAL ; HL <-- INTERVAL TIMER VALUE
DCX H ; DECREMENT TIMER
SHLD IT$VAL ; RECORD IT
MOV A,L
ORA H
JNZ EXEC ; IF (NOT EXPIRED) GOTO EXEC
STA IT$FLG ; DEACTIVATE TIMER
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI EXTI ; FLAG EXPIRED TIMER
STA EA$FLG ; RECORD FLAGS
EI ; UNGATE
JMP EXEC ; BACK TO TOP
; End action processing
EXEC2 EQU $
RAR
JC EX$A1 ; IF (SRFC) GOTO EX$A1
RAR
JC EX$A2 ; IF (ARFC) GOTO EX$A2
RAR
JC EX$A3 ; IF (STFC) GOTO EX$A3
RAR
JC EX$A4 ; IF (ATFC) GOTO EX$A4
RAR
JC EX$A5 ; IF (EXPIRED TIMER) GOTO EX$A5
RAR
JC EX$A6 ; IF (SRDD) GOTO EX$A6
RAR
JC EX$A7 ; IF (ARDD) GOTO EX$A7
JMP EXEC ; CONTINUE
; Here for synchronous receiver frame completion
EX$A1 EQU $
LHLD SR$HC ; HL <-- FRAME HEAD
PUSH H ; PRESERVE HL
DI ; GATE INTERRUPTS MOMENTARILY
CALL GCELL ; GET A FREE CELL
EI ; UNGATE
JZ EX$A11 ; IF (BUFFERS FULL) GOTO EX$A11
XCHG ; HL <-- CELL POINTER
SHLD SR$BP ; ESTABLISH NEW POINTERS
SHLD SR$HC
MVI M,0 ; RESET FORWARD POINTER
INX H ; ADVANCE POINTER
MVI M,0
LXI H,SRACT ; HL <-- SYNC. RCVR ACTIVATION COMMAND
CALL SCMDOT ; ISSUE COMMAND
EX$A11 EQU $
MVI B,0FFH-SRFC ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT SRFC
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
POP H ; RESTORE FRAME HEAD
LDA SR$FR ; A <-- FRAME RESULTS
CPI 0E0H ; EXPECTED RESULTS
JNZ EX$A12 ; IF (BAD FRAME) GOTO EX$A12
CALL LATQ ; ELSE LINK FRAME TO ASYNC. XMIT QUEUE
JMP EXEC
EX$A12 EQU $
CALL FCHN ; RELEASE BAD FRAME
JMP EXEC
; Here for asynchronous receiver frame completion
EX$A2 EQU $
MVI B,0FFH-ARFC ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT ARFC
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LHLD AR$FS ; HL <-- FRAME SIZE
MOV B,H ; COPY TO BC
MOV C,L
LHLD AR$FH ; HL <-- FRAME HEAD
CALL LSTQ ; LINK FRAME TO SYNC. XMIT QUEUE
MVI A,ADTR+ARTS+OUT1 ; DTR, RTS, AND CD FOR HOST
OUT MCR ; WRITE MODEM CONTROL REGISTER
JMP EXEC
; Here for synchronous transmitter frame completion
EX$A3 EQU $
MVI B,0FFH-STFC ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT STFC
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LDA ST$QS ; A <-- QUEUE SIZE
ORA A
JZ EX$A32 ; IF (EMPTY QUEUE) GOTO EX$A32
DCR A ; ELSE DECREMENT COUNT
STA ST$QS ; WRITE NEW COUNT
LHLD ST$QR ; HL <-- QUEUE READ POINTER
LXI D,-ST$QB ; DE <-- QUEUE BOTTOM ADDRESS
PUSH H
DAD D
POP H ; RESTORE READ POINTER
JNC EX$A31 ; IF (NOT BOTTOM) GOTO EX$A31
LXI H,ST$QT ; HL <-- QUEUE TOP ADDRESS
EX$A31 EQU $
MOV C,M ; LSB OF FRAME SIZE
INX H ; ADVANCE POINTER
MOV B,M ; MSB OF FRAME SIZE
INX H
MOV E,M ; LSB OF FRAME HEAD
INX H
MOV D,M ; MSB OF FRAME HEAD
INX H
SHLD ST$QR ; RECORD NEW POINTER
XCHG ; HL <-- FRAME HEAD
SHLD ST$BP ; RECORD IT
LXI H,STACT+2 ; HL <-- SYNC. XMTR PARAMETER POINTER
MOV M,C ; COPY LSB OF FRAME SIZE
INX H ; ADVANCE POINTER
MOV M,B ; COPY MSB OF FRAME SIZE
LXI H,STACT ; HL <-- SYNC. XMTR ACTIVATION COMMAND
CALL SCMDOT ; ISSUE COMMAND
; SET WATCHDOG TIMER HERE (LETS GO FOR A DEFAULT VALUE INITIALLY)
LXI H,WDVAL ; HL <-- DEFAULT WATCHDOG TIMER
SHLD IT$VAL ; RECORD IT
MVI A,1
STA IT$FLG ; ENABLE TIMER
INR A ; NEW STATE
STA IT$STA ; RECORD IT
JMP EXEC
; Queue empty, disable synchronous transmitter (deactivate RTS)
EX$A32 EQU $
LXI H,DARTS ; HL <-- DEACTIVATE RTS COMMAND
CALL SCMDOT ; ISSUE COMMAND
LDA TVAL ; A <-- SQUELCH TAIL TIMER VALUE
MOV L,A ; COPY VALUE TO L
XRA A
MOV H,A ; EXTEND 16 BITS
SHLD IT$VAL ; RECORD IT
INR A ; A <-- 1
STA IT$FLG ; ACTIVATE TIMER
MVI A,3 ; NEW STATE
STA IT$STA ; RECORD IT
JMP EXEC
; Here for asynchronous transmitter frame completion
EX$A4 EQU $
MVI B,0FFH-ATFC ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT ATFC
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LDA AT$QS ; A <-- QUEUE SIZE
ORA A
JZ EXEC ; IF (EMPTY QUEUE) GOTO EXEC
DCR A ; ELSE DECREMENT COUNT
STA AT$QS ; WRITE NEW COUNT
LHLD AT$QR ; HL <-- QUEUE READ POINTER
LXI D,-AT$QB ; DE <-- QUEUE BOTTOM ADDRESS
PUSH H ; PRESERVE HL
DAD D
POP H ; RESTORE QUEUE POINTER
JNC EX$A41 ; IF (NOT BOTTOM) GOTO EX$A41
LXI H,AT$QT ; HL <-- QUEUE TOP ADDRESS
EX$A41 EQU $
MOV E,M ; LSB OF FRAME HEAD
INX H
MOV D,M ; MSB OF FRAME HEAD
INX H
SHLD AT$QR ; RECORD NEW POINTER
XCHG ; HL <-- FRAME HEAD
CALL LATQ3 ; SEND FEND
JMP EXEC
; Here for timer expiration
EX$A5 EQU $
MVI B,0FFH-EXTI ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT EXTI
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LDA IT$STA ; A <-- STATE OF INTERVAL TIMER
ORA A
JZ A5$S0 ; IF (SLOT-TIME DELAY) GOTO A5$S0
DCR A
JZ A5$S1 ; IF (RELAY DELAY) GOTO A5$S1
DCR A
JZ A5$S2 ; IF (WATCH DOG) GOTO A5$S2
DCR A
JZ A5$S3 ; IF (SQUELCH DELAY) GOTO A5$S3
JMP EXEC ; IGNORE INVALID STATES
; Slot-time is expired, if channel not busy, activate RTS
A5$S0 EQU $
LXI H,RPA ; HL <-- READ PORT A COMMAND
CALL SCMDOT ; ISSUE COMMAND
CALL SRSLIN ; READ RESULTS
ANI MCD ; MASK MODEM CARRIER DETECT
JNZ EXEC ; IF (CHANNEL BUSY) GOTO EXEC
A5$S0A EQU $
LXI H,SRDIS ; HL <-- SYNC. RCVR DISABLE COMMAND
CALL SCMDOT ; ISSUE COMMAND
LXI H,STRTS ; HL <-- SYNC. XMTR RTS ENABLE COMMAND
CALL SCMDOT ; ISSUE COMMAND
LDA RVAL ; A <-- RELAY DELAY VALUE
MOV L,A ; COPY TO L
XRA A
MOV H,A ; EXTEND 16 BITS
SHLD IT$VAL ; SET DELAY VALUE
INR A ; A <-- 1
STA IT$FLG ; ACTIVATE TIMER
STA IT$STA ; RECORD NEW STATE
LXI H,ST$QS ; HL <-- QUEUE SIZE POINTER
DCR M ; DECREMENT COUNT
LHLD ST$QR ; HL <-- QUEUE READ POINTER
LXI D,-ST$QB ; DE <-- QUEUE BOTTOM ADDRESS
PUSH H
DAD D
POP H
JNC A5$S0B ; IF (NOT BOTTOM) GOTO A5$S0B
LXI H,ST$QT ; HL <-- QUEUE TOP ADDRESS
A5$S0B EQU $
MOV A,M ; LSB OF FRAME SIZE
STA STACT+2
INX H ; ADVANCE POINTER
MOV A,M ; MSB OF FRAME SIZE
STA STACT+3
INX H
MOV E,M ; LSB OF FRAME HEAD
INX H
MOV D,M ; MSB OF FRAME HEAD
INX H
SHLD ST$QR ; WRITE NEW POINTER
XCHG
SHLD ST$BP ; ESTABLISH NEW FRAME POINTER
JMP EXEC
; Relay delay time expired, start data transmission
A5$S1 EQU $
LXI H,STACT ; HL <-- SYNC. XMTR ACTIVATION COMMAND
CALL SCMDOT ; ISSUE COMMAND
LXI H,WDVAL ; HL <-- WATCHDOG TIMER VALUE
SHLD IT$VAL ; RECORD IT
MVI A,1
STA IT$FLG ; ACTIVATE TIMER
INR A ; NEW STATE
STA IT$STA ; RECORD IT
JMP EXEC
; Watchdog timer expiration, kill the transmitter
A5$S2 EQU $
LXI H,DARTS ; HL <-- DEACTIVATE RTS COMMAND
CALL SCMDOT ; ISSUE COMMAND
JMP INIT
; Squelch delay time expired, re-activate the sync. receiver
A5$S3 EQU $
LXI H,SRACT ; HL <-- SYNC. RCVR ACTIVATION COMMAND
CALL SCMDOT ; ISSUE COMMAND
JMP EXEC
; Here when synchronous receiver is discarding a frame
; because there are no available free cells.
EX$A6 EQU $
MVI B,0FFH-SRDD ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT SRDD
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LHLD SR$HC ; HL <-- FRAME HEAD
CALL FCHN ; FREE THIS CHAIN
LXI H,SRDIS ; HL <-- SYNC. RCVR DISABLE COMMAND
CALL SCMDOT ; ISSUE COMMAND
DI ; GATE INTERRUPTS MOMENTARILY
CALL GCELL ; GET A FREE CELL
EI ; UNGATE
XCHG ; HL <-- CELL POINTER
SHLD SR$BP ; ESTABLISH NEW BUFFER POINTERS
SHLD SR$HC
MVI M,0 ; RESET FORWARD POINTER
INX H ; ADVANCE POINTER
MVI M,0
LXI H,SRACT ; HL <-- SYNC. RCVR ACTIVATION COMMAND
CALL SCMDOT ; ISSUE COMMAND
XRA A ; NEW STATE (RECORDING DATA)
STA SR$STA ; RECORD IT
JMP EXEC
; Here when asynchronous receiver is discarding a frame
; because there are no available free cells.
EX$A7 EQU $
MVI B,0FFH-ARDD ; B <-- FLAG MASK
DI ; GATE INTERRUPTS MOMENTARILY
LDA EA$FLG ; A <-- END ACTION FLAGS
ANA B ; MASK OUT ARDD
STA EA$FLG ; WRITE FLAGS
EI ; UNGATE
LHLD AR$HC ; HL <-- FRAME HEAD
CALL FCHN ; FREE THIS CHAIN
MVI A,ADTR+ARTS+OUT1 ; DTR, RTS, AND CD FOR HOST
OUT MCR ; WRITE MODEM CONTROL REGISTER
JMP EXEC
; PAGE
; Queue management routines for synchronous & asynchronous output
; Link a frame to the synchronous transmit queue
LSTQ EQU $
XCHG ; DE <-- ADDRESS OF FRAME
LHLD ST$QW ; HL <-- QUEUE WRITE POINTER
MOV M,C ; LSB OF FRAME SIZE
INX H ; ADVANCE POINTER
MOV M,B ; MSB OF FRAME SIZE
INX H
MOV M,E ; LSB OF FRAME HEAD
INX H
MOV M,D ; MSB OF FRAME HEAD
INX H ; HL <-- NEXT QUEUE ENTRY
LXI D,-ST$QB ; DE <-- QUEUE BOTTOM ADDRESS
PUSH H ; PRESERVE HL
DAD D
POP H ; RESTORE QUEUE POINTER
JNC LSTQ1 ; IF (NOT BOTTOM) GOTO LSTQ1
LXI H,ST$QT ; HL <-- QUEUE TOP ADDRESS
LSTQ1 EQU $
SHLD ST$QW ; WRITE NEW QUEUE POINTER
LXI H,ST$QS ; HL <-- QUEUE SIZE POINTER
INR M ; INCREMENT QUEUE SIZE
RET
; Link a frame to the asynchronous transmit queue
LATQ EQU $
LDA AT$QS ; A <-- QUEUE SIZE
ORA A
JNZ LATQ1 ; IF (QUEUED FRAMES) GOTO LATQ1
LDA AT$STA ; A <-- STATE OF ASYNC. TRANSMITTER
CPI 0FFH
JZ LATQ3 ; IF (XMTR INACTIVE) GOTO LATQ3
LATQ1 EQU $
XCHG ; DE <-- ADDRESS OF FRAME
LHLD AT$QW ; HL <-- QUEUE WRITE POINTER
MOV M,E ; LSB OF FRAME HEAD
INX H ; ADVANCE POINTER
MOV M,D ; MSB OF FRAME HEAD
INX H ; HL <-- NEXT QUEUE ENTRY
LXI D,-AT$QB ; DE <-- QUEUE BOTTOM ADDRESS
PUSH H ; PRESERVE HL
DAD D
POP H ; RESTORE QUEUE POINTER
JNC LATQ2 ; IF (NOT BOTTOM) GOTO LATQ2
LXI H,AT$QT ; HL <-- QUEUE TOP ADDRESS
LATQ2 EQU $
SHLD AT$QW ; WRITE NEW POINTER
LXI H,AT$QS ; HL <-- QUEUE SIZE POINTER
INR M ; INCREMENT QUEUE SIZE
RET
; Queue is empty and asynchronous transmitter is
; inactive. Don't queue this entry, just send it out.
LATQ3 EQU $
SHLD AT$BP ; ESTABLISH NEW POINTER
MVI A,FEND ; A <-- FEND
OUT THR ; WRITE TRANSMIT HOLDING REGISTER
MVI A,4 ; NEW STATE (OPENING FRAME)
STA AT$STA ; RECORD IT
MVI A,ERI+ETI+ELI+EMI ; 8250 INTERRUPT ENABLE FLAGS
OUT IER ; WRITE INTERRUPT ENABLE REGISTER
RET
; PAGE
; Buffer management routines
; Allocate a free cell
GCELL EQU $
LHLD FL$HC ; HL <-- HEAD CELL ON FREE LIST
MOV A,H ; MSB OF ADDRESS
ORA L ; LSB OF ADDRESS
JZ GC$EL ; IF (EMPTY LIST) GOTO GC$EL
XCHG ; DE <-- FREE CELL
LXI H,FL$HC ; HL <-- HEAD CELL POINTER
LDAX D ; A <-- LSB OF NEXT FREE CELL
MOV M,A ; COPY TO FL$HC
INX D ; ADVANCE POINTERS
INX H
LDAX D ; A <-- MSB OF NEXT FREE CELL
MOV M,A ; COPY TO FL$HC
DCX D ; RESET FREE CELL POINTER
GC$EL EQU $
RET
; Attach a cell to the free list
FCELL EQU $
LXI H,FL$HC ; HL <-- HEAD CELL POINTER
MOV C,M ; C <-- LSB OF FIRST CELL
MOV M,E ; UPDATE LSB OF FL$HC
INX H ; ADVANCE POINTER
MOV B,M ; B <-- MSB OF FIRST CELL
MOV M,D ; UPDATE MSB OF FL$HC
XCHG ; HL <-- RELEASED CELL
MOV E,M ; E <-- LSB OF NEXT CELL
MOV M,C ; COPY LSB OF OLD HC TO NEW
INX H ; ADVANCE POINTER
MOV D,M ; D <-- MSB OF NEXT CELL
MOV M,B ; COPY MSB OF OLD HC TO NEW
INX H ; ADVANCE POINTER
MVI M,0 ; RESET NBYTE
INX H
MVI M,0 ; RESET NREAD
XCHG ; HL <-- NEXT CELL IN CHAIN
RET
; Attach a chain of cells to the free list
FCHN EQU $
XCHG ; DE <-- CELL TO BE RELEASED
DI ; GATE INTERRUPTS MOMENTARILY
CALL FCELL ; FREE IT UP
EI ; UNGATE
MOV A,H ; MSB OF FORWARD POINTER FROM CELL
ORA L ; LSB OF SAME
JNZ FCHN ; IF (MORE CELLS) GOTO FCHN
RET
; PAGE
; Extract a character from the buffer referenced by HL
GCHAR EQU $
PUSH H ; PRESERVE HL
INX H ; SKIP FORWARD POINTER
INX H
MOV A,M ; A <-- NBYTES
INX H ; ADVANCE POINTER
SUB M ; CHECK NREAD
JZ GC$BE ; IF (BUFFER EXHAUSTED) GOTO GC$BE
PUSH D ; PRESERVE DE
INR M ; INCREMENT NREAD
MOV E,M ; E <-- NREAD
XRA A
MOV D,A ; EXTEND 16 BITS
DAD D ; HL <-- HL + DE
INR A ; RESET 'Z' FLAG
MOV A,M ; A <-- CHARACTER
POP D ; RESTORE DE
POP H ; RESTORE HL
RET
; Follow chain to next buffer
GC$BE EQU $
POP H ; RESTORE HL
PUSH D ; PRESERVE DE & BC
PUSH B
XCHG ; DE <-- BUFFER POINTER
CALL FCELL ; RELEASE THIS CELL
POP B ; RESTORE BC & DE
POP D
MOV A,H ; MSB OF NEXT CELL IN CHAIN
ORA L ; LSB OF SAME
JNZ GCHAR ; IF (GOOD BUFFER) GOTO GCHAR
RET ; ELSE RETURN WITH 'Z' FLAG SET
; Stuff a character into the buffer referenced by HL
PCHAR EQU $
PUSH D ; PRESERVE DE
PUSH PSW ; PRESERVE PSW (CHARACTER)
INX H ; SKIP FORWARD POINTER
INX H
MVI A,124 ; A <-- BUFFER LIMIT
SUB M ; A <-- 124 - NBYTES
CZ PC$NB ; IF (NEED BUFFER) CALL PC$NB
PUSH H ; PRESERVE HL (BUFFER POINTER)
INR M ; INCREMENT NBYTES
MOV E,M ; E <-- NBYTES
XRA A
MOV D,A ; EXTEND 16 BITS
INX H ; SKIP NBYTES
DAD D ; HL <-- HL + DE
POP D ; RESTORE POINTER
POP PSW ; RESTORE CHARACTER
MOV M,A ; COPY CHARACTER TO BUFFER
XCHG ; HL <-- ORIGINAL POINTER
DCX H ; ADJUST POINTER
DCX H
POP D ; RESTORE DE
XRA A
INR A ; RESET 'Z' FLAG
RET
; Here if PCHAR needs a new buffer
PC$NB EQU $
PUSH H ; PRESERVE HL
CALL GCELL ; FREE CELL POINTER TO DE
POP H ; RESTORE HL
JZ PC$BF ; IF (BUFFERS FULL) GOTO PC$BF
DCX H
MOV M,D ; COPY MSB TO PREVIOUS CELL
DCX H ; ADVANCE POINTER
MOV M,E ; COPY LSB TO PREVIOUS CELL
XCHG ; HL <-- NEW BUFFER POINTER
MVI M,0 ; RESET FORWARD POINTER
INX H ; ADVANCE POINTER
MVI M,0
INX H
RET
; Here if free cell not available
PC$BF EQU $
POP PSW ; PURGE RETURN ADDRESS FROM STACK
POP PSW ; RESTORE CHARACTER
POP D ; RESTORE DE
XRA A ; SET 'Z' FLAG
RET
; PAGE
; Asynchronous Interrupt Response Code
AIRC EQU $
PUSH PSW ; SAVE PROGRAM STATUS WORD
IN IIR ; READ INTERRUPT IDENTIFICATION REG.
RAR ; RIGHT JUSTIFY ID BITS
ANI 00000011B ; MASK
JZ IRC$AM ; IF (MODEM STATUS) GOTO IRC$AM
DCR A
JZ IRC$AT ; IF (XMTR EMPTY) GOTO IRC$AT
DCR A
JZ IRC$AR ; IF (DATA READY) GOTO IRC$AR
; Here for line status interrupt
IRC$AL EQU $
IN LSR ; READ LINE STATUS REGISTER
ANI BI ; MASK BREAK INTERRUPT
; Treat overrun, parity, framing errors as data ready
JZ IRC$AR ; IF (NOT BI) GOTO IRC$AR
IN RBR ; FLUSH NULL FROM BUFFER
POP PSW ; RESTORE PSW
EI ; UNGATE
RET ; RETURN FROM INTERRUPT
; Here for modem status interrupt
IRC$AM EQU $
IN MSR ; READ MODEM STATUS
PUSH PSW ; SAVE STATUS
ANI DCTS+DDSR ; MASK SOURCE BITS OF INTEREST
RAR
RAR
JM AM$1 ; IF (DELTA CTS) GOTO AM$1
JC INIT ; IF (HOST LOST) GOTO INIT
; Ignore other sources of this interrupt
POP PSW ; REMOVE STATUS FROM STACK
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here if Clear-To-Send has changed state
AM$1 EQU $
POP PSW ; FETCH MODEM STATUS FROM STACK
ANI TCTS ; MASK TERMINAL CLEAR-TO-SEND STATUS
JNZ AM$2 ; IF (CLEAR-TO-SEND) GOTO AM$2
; Host has full buffer or something, stop sending
MVI A,ERI+ELI+EMI ; INTERRUPT ENABLE FLAGS
OUT IER ; WRITE INTERRUPT ENABLE REGISTER
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Host is now ready to receive data again
AM$2 EQU $
LDA AT$STA ; A <-- STATE OF TRANSMITTER
CPI 0FFH
JZ AM$3 ; IF (INACTIVE) GOTO AM$3
MVI A,ERI+ETI+ELI+EMI ; INTERRUPT ENABLE FLAGS
OUT IER ; WRITE INTERRUPT ENABLE REGISTER
AM$3 EQU $
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here for asynchronous transmit interrupt
IRC$AT EQU $
LDA AT$STA ; A <-- STATE OF TRANSMITTER
ORA A
JZ AT$S0 ; IF (NOT ESCAPED) GOTO AT$S0
DCR A
JZ AT$S1 ; IF (SENDING TFESC) GOTO AT$S1
DCR A
JZ AT$S2 ; IF (SENDING TFEND) GOTO AT$S2
DCR A
JZ AT$S3 ; IF (END OF FRAME) GOTO AT$S3
DCR A
JZ AT$S4 ; IF (OPENING FRAME) GOTO AT$S4
JMP RST1+1 ; IGNORE INACTIVE STATE
; Here for normal data transmission (not currently escaped)
AT$S0 EQU $
PUSH H ; PRESERVE HL
LHLD AT$BP ; HL <-- BUFFER POINTER
CALL GCHAR ; MOVE NEXT CHARACTER TO A
SHLD AT$BP ; SAVE UPDATED POINTER
POP H ; RESTORE HL
JZ AT$S0S3 ; IF (END OF FRAME) GOTO AT$S0S3
CPI FESC
JZ AT$S0S1 ; IF (CHAR = FESC) GOTO AT$S0S1
CPI FEND
JZ AT$S0S2 ; IF (CHAR = FEND) GOTO AT$S0S2
OUT THR ; WRITE CHARACTER
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Send FESC and change state to 1
AT$S0S1 EQU $
OUT THR ; WRITE FESC
MVI A,1 ; NEW STATE
STA AT$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Send FESC and change state to 2
AT$S0S2 EQU $
MVI A,FESC ; A <-- FESC
OUT THR ; WRITE
MVI A,2 ; NEW STATE
STA AT$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Send FEND and change state to 3
AT$S0S3 EQU $
MVI A,FEND ; A <-- FEND
OUT THR ; WRITE
MVI A,3 ; NEW STATE
STA AT$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Send TFESC (FESC was last character sent)
AT$S1 EQU $
MVI A,TFESC ; A <-- TFESC
OUT THR ; WRITE
XRA A ; NEW STATE (NOT ESCAPED)
STA AT$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Send TFEND (FESC was last character sent)
AT$S2 EQU $
MVI A,TFEND ; A <-- TFEND
OUT THR ; WRITE
XRA A ; NEW STATE (NOT ESCAPED)
STA AT$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here for end of frame transmission - FEND already sent
AT$S3 EQU $
MVI A,ERI+ELI+EMI ; RCVR, LINE, AND MODEM ENABLE FLAGS
OUT IER ; WRITE INTERRUPT ENABLE REGISTER
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI ATFC ; SET ASYNC. XMTR FRAME COMPLETE
STA EA$FLG ; WRITE FLAGS
MVI A,0FFH ; NEW STATE (ASYNC. XMTR DISABLED)
STA AT$STA ; RECORD IT
POP PSW
EI
RET
; Here for opening frame, send data frame control byte
AT$S4 EQU $
XRA A ; A <-- 0
OUT THR ; WRITE CONTROL BYTE
STA AT$STA ; ALSO IS OUR NEW STATE
POP PSW
EI
RET
; Here for asynchronous receive interrupt
IRC$AR EQU $
LDA AR$STA ; A <-- STATE OF RECEIVER
ORA A
JZ AR$S0 ; IF (EXPECTING DATA) GOTO AR$S0
DCR A
JZ AR$S1 ; IF (ESCAPED) GOTO AR$S1
DCR A
JZ AR$S2 ; IF (EXPECTING COMMAND) GOTO AR$S2
DCR A
JZ AR$S3 ; IF (EXPECTING P-VALUE) GOTO AR$S3
DCR A
JZ AR$S4 ; IF (EXPECTING S-VALUE) GOTO AR$S4
DCR A
JZ AR$S5 ; IF (EXPECTING T-VALUE) GOTO AR$S5
DCR A
JZ AR$S6 ; IF (EXPECTING TXDELAY) GOTO AR$S6
; Here if waiting for FEND to begin a new frame
AR$S7 EQU $
IN RBR ; READ CHARACTER
CPI FEND
JNZ RST1+1 ; IF (NOT FEND) RETURN FROM INTERRUPT
MVI A,2 ; NEW STATE
STA AR$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here if expecting frame data
AR$S0 EQU $
IN RBR ; READ CHARACTER
CPI FESC
JZ AR$S0S1 ; IF (DATA = FESC) GOTO AR$S0S1
CPI FEND
JZ AR$S0S2 ; IF (DATA = FEND) GOTO AR$S0S2
PUSH H ; PRESERVE HL
LHLD AR$BP ; HL <-- BUFFER POINTER
CALL PCHAR ; STORE CHARACTER
JZ AR$S0S7 ; IF (BUFFERS FULL) GOTO AR$S0A
SHLD AR$BP ; RECORD NEW POINTER
LHLD AR$FSZ ; HL <-- FRAME SIZE
INX H ; INCREMENT COUNT
SHLD AR$FSZ ; RECORD IT
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here we deal with a serious problem. We are in the middle
; of a frame and filled our current buffer, but alas, there
; are no free cells to allocate. Return all buffers in this
; frame to the free cell list and hope we recover.
AR$S0S7 EQU $
AR$S1S7 EQU $
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI ARDD ; ASYNC. RECEIVER DISCARDING DATA
STA EA$FLG ; SAVE UPDATED FLAGS
MVI A,ADTR+OUT1 ; DTR & CD, NO RTS
OUT MCR ; WRITE MODEM CONTROL REGISTER
POP H ; RESTORE HL
; Here we just change state to wait for the next incoming
; frame and hope by then that we have recovered some cells.
AR$S2S7 EQU $
MVI A,7 ; NEW STATE
STA AR$STA ; RECORD NEW STATE
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; FESC was just detected. Change state to 1 and see what follows.
AR$S0S1 EQU $
MVI A,1 ; NEW STATE
STA AR$STA ; RECORD IT
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; FEND was just detected. Move frame to synch. transmit queue.
AR$S0S2 EQU $
PUSH H ; PRESERVE HL
LHLD AR$HC ; HL <-- HEAD CELL POINTER
SHLD AR$FH ; SAVE POINTER FOR EXEC
LHLD AR$FSZ ; HL <-- FRAME SIZE
SHLD AR$FS ; SAVE FOR EXECUTIVE
MVI A,2 ; NEW STATE
STA AR$STA ; RECORD IT
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI ARFC ; ASYNC. RECEIVER FRAME COMPLETE
STA EA$FLG ; SAVE UPDATED FLAGS
MVI A,ADTR+OUT1 ; DTR & CD, NO RTS
OUT MCR ; WRITE MODEM CONTROL REGISTER
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; This character follows an FESC, must be TFESC or TFEND
AR$S1 EQU $
XRA A ; NEW STATE
STA AR$STA ; RECORD IT
IN RBR ; READ CHARACTER
CPI TFESC
JZ AR$S1A ; IF (DATA = TFESC) GOTO AR$S1A
CPI TFEND
JNZ RST1+1 ; IF (DATA <> TFEND) RETURN FROM INT.
; Character was TFEND. Translate it.
MVI A,FEND ; A <-- FEND
JMP AR$S1B ; STORE IT
; Character was TFESC. Translate it.
AR$S1A EQU $
MVI A,FESC ; A <-- FESC
AR$S1B EQU $
PUSH H ; PRESERVE HL
LHLD AR$BP ; HL <-- BUFFER POINTER
CALL PCHAR ; STORE CHARACTER
JZ AR$S1S7 ; IF (BUFFERS FULL) GOTO AR$S1S7
SHLD AR$BP ; RECORD NEW POINTER
LHLD AR$FSZ ; HL <-- FRAME SIZE
INX H ; INCREMENT COUNT
SHLD AR$FSZ ; RECORD IT
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Last character seen was FEND. Look for frame command.
AR$S2 EQU $
IN RBR ; READ CHARACTER
CPI FEND
JZ RST1+1 ; RETURN FROM INTERRUPT
ORA A
JZ AR$S2S0 ; IF (DATA FRAME) GOTO AR$S2S0
DCR A
JZ AR$S2A ; IF (R COMMAND) GOTO AR$S2A
DCR A
JZ AR$S2B ; IF (P COMMAND) GOTO AR$S2B
DCR A
JZ AR$S2C ; IF (S COMMAND) GOTO AR$S2C
DCR A
JZ AR$S2D ; IF (T COMMAND) GOTO AR$S2D
JMP AR$S2S7 ; BOGUS COMMAND, WAIT FOR FEND
; Here if TxDelay value to follow
AR$S2A EQU $
MVI A,6 ; NEW STATE
STA AR$STA ; RECORD IT
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here if Persistence value to follow
AR$S2B EQU $
MVI A,3
STA AR$STA
POP PSW
EI
RET
; Here if Slot-time value to follow
AR$S2C EQU $
MVI A,4
STA AR$STA
POP PSW
EI
RET
; Here if Squelch-delay value to follow
AR$S2D EQU $
MVI A,5
STA AR$STA
POP PSW
EI
RET
; Here when data to follow
AR$S2S0 EQU $
PUSH H ; PRESERVE HL
CALL GCELL ; GET A FREE CELL
JZ AR$S2S7 ; IF (BUFFERS FULL) GOTO AR$S0S7
XCHG ; HL <-- CELL POINTER
SHLD AR$BP ; ESTABLISH NEW BUFFER POINTERS
SHLD AR$HC
MVI M,0 ; RESET FORWARD POINTER
INX H ; ADVANCE POINTER
MVI M,0
LXI H,0 ; HL <-- 0
SHLD AR$FSZ ; RESET FRAME SIZE
POP H ; RESTORE HL
XRA A ; NEW STATE
STA AR$STA ; RECORD IT
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Load a persistence value
AR$S3 EQU $
IN RBR
STA PVAL
MVI A,2
STA AR$STA
POP PSW
EI
RET
; Load a slot-time value
AR$S4 EQU $
IN RBR
STA SVAL
MVI A,2
STA AR$STA
POP PSW
EI
RET
; Load a squelch-delay value
AR$S5 EQU $
IN RBR
STA TVAL
MVI A,2
STA AR$STA
POP PSW
EI
RET
; Load a Tx relay delay value
AR$S6 EQU $
IN RBR
STA RVAL
MVI A,2
STA AR$STA
POP PSW
EI
RET
; PAGE
; Synchronous Transmitter Interrupt Response Code
STIRC EQU $
PUSH PSW ; PRESERVE PROGRAM STATUS WORD
PUSH H ; SAME WITH HL
IN STAT73 ; READ STATUS
ANI TXIRA
JNZ ST$CI ; IF (END-OF-FRAME) GOTO ST$CI
; Here if transmitter waiting for data
LHLD ST$BP ; HL <-- BUFFER POINTER
CALL GCHAR ; MOVE NEXT CHARACTER TO A
OUT TXDR73 ; WRITE CHARACTER
SHLD ST$BP ; SAVE UPDATED POINTER
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here for frame completion interrupt
ST$CI EQU $
IN TXIR73 ; READ RESULTS
STA ST$FR ; SAVE RESULTS POINTER
PUSH D ; PRESERVE DE
LHLD ST$BP ; HL <-- CURRENT BUFFER POINTER
XCHG ; MOVE POINTER TO DE
CALL FCELL ; FREE THIS CELL
POP D ; RESTORE DE
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI STFC ; SYNC. TRANSMITTER FRAME COMPLETE
STA EA$FLG ; SAVE UPDATED FLAGS
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; PAGE
; Synchronous Receiver Interrupt Response Code
SRIRC EQU $
PUSH PSW ; PRESERVE PROGRAM STATUS WORD
LDA SR$STA ; A <-- STATE OF SYNC. RECEIVER
ORA A
JNZ SR$S1 ; IF (DISCARDING DATA) GOTO SR$S1
; Here if synchronous receiver state 0, recording data
SR$S0 EQU $
PUSH H ; PRESERVE HL
IN STAT73 ; READ STATUS
ANI RXIRA
JNZ SR$CI ; IF (END-OF-FRAME) GOTO SR$CI
; Here if receiver has data to unload
IN RXDR73 ; READ CHARACTER
LHLD SR$BP ; HL <-- BUFFER POINTER
CALL PCHAR ; COPY CHARACTER TO BUFFER
JZ SR$BF ; IF (BUFFERS FULL) GOTO SR$BF
SHLD SR$BP ; SAVE UPDATED POINTER
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here for frame completion interrupt
SR$CI EQU $
IN RXIR73 ; READ FRAME STATUS
STA SR$FR ; SAVE IT FOR EXEC
PUSH B ; PRESERVE BC
SR$CIA EQU $
IN STAT73 ; READ STATUS
MOV B,A ; COPY STATUS TO B
ANI RINTP
JZ SR$CIB ; IF (RESULTS COMPLETE) GOTO SR$CIB
MOV A,B ; RESTORE STATUS
ANI RXIRA
JZ SR$CIA ; IF (NO RESULTS) GOTO SR$CIA
; Ready to read one byte of results code
IN RXIR73 ; READ RESULTS
JMP SR$CIA ; WAIT FOR MORE, IF ANY
; Results are now complete
SR$CIB EQU $
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI SRFC ; SYNC. RECEIVER FRAME COMPLETE
STA EA$FLG ; SAVE UPDATED FLAGS
POP B ; RESTORE BC
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Again we must deal with being in the middle of a frame
; with no available free cells to continue. Release the
; cells for this frame and cease reception till we recover.
SR$BF EQU $
MVI A,1 ; NEW STATE
STA SR$STA ; RECORD IT
LDA EA$FLG ; A <-- END ACTION FLAGS
ORI SRDD ; SYNC. RECEIVER DISCARDING DATA
STA EA$FLG ; SAVE UPDATED FLAGS
POP H ; RESTORE HL
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here if synchronous receiver state 1, discarding data
SR$S1 EQU $
IN STAT73 ; READ STATUS
ANI RXIRA
JNZ SR$DR ; IF (END-OF-FRAME) GOTO SR$DR
; Here if receiver has data to unload
IN RXDR73 ; READ CHARACTER
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; Here if discarding results
SR$DR EQU $
IN RXIR73 ; READ FRAME RESULTS
PUSH B ; PRESERVE BC
SR$DRA EQU $
IN STAT73 ; READ STATUS
MOV B,A ; COPY STATUS TO B
ANI RINTP
JZ SR$DRB ; IF (RESULTS COMPLETE) GOTO SR$DRB
MOV A,B ; RESTORE STATUS
ANI RXIRA
JZ SR$DRA ; IF (NO RESULTS) GOTO SR$DRA
; Ready to read one byte of results code
IN RXIR73 ; READ RESULTS
JMP SR$DRA ; WAIT FOR MORE, IF ANY
; Results are now complete
SR$DRB EQU $
POP B ; RESTORE BC
POP PSW
EI
RET ; RETURN FROM INTERRUPT
; PAGE
; Command and Immediate Results routines for 8273
SCMDOT EQU $
MOV B,M ; B <-- PARAMETER COUNT
INX H ; ADVANCE TO COMMAND BYTE
CMD1 EQU $
IN STAT73 ; READ STATUS
RLC ; MOVE CBSY INTO CARRY
JC CMD1 ; IF (CBSY <> 0) GOTO CMD1
MOV A,M ; A <-- COMMAND BYTE
OUT CMND73 ; WRITE COMMAND
CMD2 EQU $
MOV A,B ; A <-- PARAMETER COUNT
ANA A
RZ ; IF (COUNT = 0) RETURN
INX H ; ADVANCE POINTER
DCR B ; DECREMENT PARAMETER COUNT
CMD3 EQU $
IN STAT73 ; READ STATUS
ANI CPBF ; MASK COMMAND PARAMETER BUFFER FULL
JNZ CMD3 ; IF (CPBF <> 0) GOTO CMD3
MOV A,M ; A <-- PARAMETER
OUT PARM73 ; WRITE PARAMETER
JMP CMD2 ; CHECK FOR MORE PARAMETERS
SRSLIN EQU $
IN STAT73 ; READ STATUS
ANI CRBF ; MASK COMMAND RESULTS BUFFER FULL
JZ SRSLIN ; IF (CRBF = 0) GOTO SRSLIN
IN RESL73 ; READ RESULTS
RET
; PAGE
; Messages
;
; TNC's SIGNATURE
TNCID EQU $
DB 'VADCG/ASHBY-2716 Terminal Node Controller'
DB CR,LF
DB 'KISS Protocol Firmware Version 1.03 08 FEB 87'
DB CR,LF,LF
;
; COMMAND SEQUENCES FOR 8273 CONTROLLER
DTRANS DB 1,97H,1
OPMODE DB 1,91H,03H
SERIO DB 1,0A0H,1
SSDTR DB 1,0A3H,4
STRTS DB 1,0A3H,1
DARTS DB 1,63H,0FEH
SRDIS DB 0,0C5H
RPA DB 0,22H
END